package org.amos.server.modules.upms.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.amos.core.basic.annotation.Log;
import org.amos.core.basic.constant.SystemConstant;
import org.amos.core.basic.exception.ServiceException;
import org.amos.core.basic.utils.AmosUtils;
import org.amos.core.basic.utils.JsonUtils;
import org.amos.core.frame.utils.RedisUtils;
import org.amos.filestorage.enums.FilePlatformEnum;
import org.amos.filestorage.platform.AbstractFilePlatform;
import org.amos.filestorage.platform.FilePlatform;
import org.amos.filestorage.platform.FilePlatformConfig;
import org.amos.filestorage.platform.FilePlatformManager;
import org.amos.filestorage.platform.config.LocalFilePlatformConfig;
import org.amos.server.modules.upms.dto.ConfigFileStorageDTO;
import org.amos.server.modules.upms.entity.ConfigFileStorage;
import org.amos.server.modules.upms.mapper.ConfigFileStorageMapper;
import org.amos.server.modules.upms.service.IConfigFileStorageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static org.amos.server.constant.SysCacheConstant.SYS_CACHE_FORMAT;
import static org.amos.server.constant.SysCacheConstant.SYS_CONFIG_MAIL_KEY;

@Service
@RequiredArgsConstructor
public class ConfigFileStorageServiceImpl extends ServiceImpl<ConfigFileStorageMapper, ConfigFileStorage> implements IConfigFileStorageService {

    @Value("${file-storage.local.upload-path}")
    private String uploadPath;

    private final RedisUtils redisUtils;

    private final FilePlatformManager platformManager;
    @Override
    public FilePlatform getDefaultPlatform() {
        ConfigFileStorage defaultConfig = getDefaultConfig();
        if (Objects.nonNull(defaultConfig)) {
            FilePlatformConfig filePlatformConfig = this.parseConfig(defaultConfig.getPlatform(), defaultConfig.getConfig());
            String platform = FilePlatformEnum.getByPlatformByCode(defaultConfig.getPlatform());
            AbstractFilePlatform<FilePlatformConfig> filePlatform = platformManager.getPlatform(defaultConfig.getNo(), platform, filePlatformConfig);
            return filePlatform;
        }
        return null;
    }

    @Override
    public FilePlatform getPlatformByConfigNo(String configNo) {
        Assert.state(StrUtil.isNotBlank(configNo), "configNo is null");
        ConfigFileStorage config = this.getConfigByNo(configNo);
        if (Objects.nonNull(config)) {
            FilePlatformConfig filePlatformConfig = this.parseConfig(config.getPlatform(), config.getConfig());
            String platform = FilePlatformEnum.getByPlatformByCode(config.getPlatform());
            AbstractFilePlatform<FilePlatformConfig> filePlatform = platformManager.getPlatform(config.getNo(), platform, filePlatformConfig);
            return filePlatform;
        }
        return null;
    }

    @Override
    public ConfigFileStorage findById(Long id) {
        return super.getById(id);
    }

    @Override
    public ConfigFileStorage getDefaultConfig() {
        QueryWrapper<ConfigFileStorage> qw = new QueryWrapper();
        qw.eq(AmosUtils.toDbField(ConfigFileStorage::getIsDefault), SystemConstant.SYS_EFFECTIVE_STATUS);
        return super.getOne(qw);
    }

    @Override
    public ConfigFileStorage getConfigByNo(String configNo) {
        QueryWrapper<ConfigFileStorage> qw = new QueryWrapper();
        qw.eq(AmosUtils.toDbField(ConfigFileStorage::getNo), configNo);
        return super.getOne(qw);
    }

    @Override
    @Log(value = "[更新文件存储配置]")
    public Boolean saveOrUpdateConfigFileStorage(ConfigFileStorageDTO dto) {
        ConfigFileStorage entity = AmosUtils.copy(dto, ConfigFileStorage.class);
        // 本地存储basePath为系统配置
        if (FilePlatformEnum.LOCAL.getCode().equals(dto.getPlatform())) {
            LocalFilePlatformConfig config = (LocalFilePlatformConfig) parseConfig(dto.getPlatform(), JsonUtils.objectToJson(dto.getConfig()));
            config.setBasePath(uploadPath);
            dto.setConfig(JsonUtils.jsonToPojo(JsonUtils.objectToJson(config), Map.class));
        }
        // 校验配置信息合法性
        validateConfig(dto.getPlatform(), dto.getConfig());
        entity.setConfig(JsonUtils.objectToJson(dto.getConfig()));
        // 新增检查配置编码
        if (StrUtil.isNotBlank(entity.getNo())) {
            QueryWrapper<ConfigFileStorage> qw = new QueryWrapper();
            if (Objects.nonNull(entity.getId())) {
                qw.ne(AmosUtils.toDbField(ConfigFileStorage::getId), entity.getId());
            }
            qw.eq(AmosUtils.toDbField(ConfigFileStorage::getNo), entity.getNo());
            long count = super.count(qw);

            if (count > 0) {
                throw new ServiceException("配置编码已存在,请勿重复添加!");
            }
        }
        if (SystemConstant.SYS_EFFECTIVE_STATUS.equals(entity.getIsDefault())) {
            QueryWrapper<ConfigFileStorage> qw = new QueryWrapper();
            if (Objects.nonNull(entity.getId())) {
                qw.ne(AmosUtils.toDbField(ConfigFileStorage::getId), entity.getId());
            }
            qw.eq(AmosUtils.toDbField(ConfigFileStorage::getIsDefault), SystemConstant.SYS_EFFECTIVE_STATUS);
            long count = super.count(qw);

            if (count > 0) {
                throw new ServiceException("默认配置已存在,请勿重复添加!");
            }
        }

        return super.saveOrUpdate(entity);
    }

    @Override
    public Boolean test(Set<Long> ids) {
        QueryWrapper<ConfigFileStorage> qw = new QueryWrapper();
        qw.in(AmosUtils.toDbField(ConfigFileStorage::getId), ids);
        qw.select("no");
        List<ConfigFileStorage> list = super.list(qw);
        try {
            list.forEach(x -> {
                FilePlatform platform = this.getPlatformByConfigNo(x.getNo());
                byte[] bytes = ResourceUtil.readBytes("file/test.json");
                String path = DateUtil.format(new Date(), "yyyy/MM/dd") + "/"+ UUID.randomUUID() + "_test.json";
                platform.upload(bytes, path, MediaType.APPLICATION_JSON_VALUE);
            });
        }catch (Exception e) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @Override
    @Log(value = "[删除文件存储配置]")
    public Boolean remove(Set<Long> ids) {
        QueryWrapper<ConfigFileStorage> qw = new QueryWrapper();
        qw.in(AmosUtils.toDbField(ConfigFileStorage::getId), ids);
        List<ConfigFileStorage> list = super.list(qw);
        // 删除数据库信息
        UpdateWrapper<ConfigFileStorage> uw = new UpdateWrapper<>();
        uw.in(AmosUtils.toDbField(ConfigFileStorage::getId), ids).set(AmosUtils.toDbField(ConfigFileStorage::getIsDeleted), SystemConstant.SYS_DELETE_FLAG_ALREADY);
        super.update(uw);
        // 删除redis信息
        List<String> noList = list.stream().map(entity -> String.format(SYS_CONFIG_MAIL_KEY + SYS_CACHE_FORMAT, entity.getNo())).collect(Collectors.toList());
        List<String> keyList = ids.stream().map(id -> String.format(SYS_CONFIG_MAIL_KEY + SYS_CACHE_FORMAT, id)).collect(Collectors.toList());
        keyList.addAll(noList);
        redisUtils.del(keyList.toArray(new String[]{}));
        return Boolean.TRUE;
    }

    /**
     * 校验配置信息是否合法
     * @param platform
     * @param config
     * @return
     */
    private void validateConfig(Integer platform, Map<String, Object> config) {
        Class<? extends FilePlatformConfig> configClass = FilePlatformEnum.getByPlatform(platform)
                .getConfigClass();
        FilePlatformConfig platformConfig = JsonUtils.jsonToPojo(JsonUtils.objectToJson(config), configClass);
        Assert.state(Objects.nonNull(platformConfig), "config is Illegal param");
    }

    /**
     * 将json字符串配置信息转换成对应文件存储平台
     * @param platform
     * @param config
     * @return
     */
    private FilePlatformConfig parseConfig(Integer platform, String config) {
        Class<? extends FilePlatformConfig> configClass = FilePlatformEnum.getByPlatform(platform)
                .getConfigClass();
        FilePlatformConfig platformConfig = JsonUtils.jsonToPojo(config, configClass);
        Assert.state(Objects.nonNull(platformConfig), "config is Illegal param");
        return platformConfig;
    }
}